package com.fary.web.request;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fary.common.ResponseVo;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.MethodParameter;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.http.MediaType;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;


@ControllerAdvice
@EnableConfigurationProperties(ResponseBodyHandler.ResponseBodyHandlerProperties.class)
public class ResponseBodyHandler implements ResponseBodyAdvice {
    @Autowired
    private ResponseBodyHandlerProperties properties;

    @Override
    public Object beforeBodyWrite(Object resBody, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest req, ServerHttpResponse res) {
        String path = req.getURI().getPath();
        if (path.startsWith("/swagger")
                || path.startsWith("/actuator")
                || path.startsWith("/webjars")
                || "/v2/api-docs".equals(path) || mediaType.toString().equals(MediaType.APPLICATION_XML_VALUE)) {
            return resBody;
        } else if ("/error".equals(path)) {
            JSONObject obj = JSONUtil.parseObj(JSONUtil.toJsonStr(resBody));
            return ResponseVo.ok(obj.getStr("message"));
        }

        boolean flag = isNeedHandler(path);
        if (flag) {
            if (StringHttpMessageConverter.class.isAssignableFrom(aClass)) {
                return JSONUtil.toJsonStr(ResponseVo.ok(resBody));
            } else if (resBody instanceof ResponseVo || ResourceHttpMessageConverter.class.isAssignableFrom(aClass)) {
                return resBody;
            } else {
                return ResponseVo.ok(resBody);
            }
        } else {
            return resBody;
        }
    }

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    public boolean isNeedHandler(String uri) {
        PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();
        for (String includeUrl : properties.getExcludedPaths()) {
            if (patternResolver.getPathMatcher().match(includeUrl, uri)) {
                return false;
            }
        }
        return true;
    }

    @ConfigurationProperties("response.handler")
    @Data
    public static class ResponseBodyHandlerProperties {
        private String[] excludedPaths = {
                "/actuator/**",
                "/swagger-ui.html/**",
                "/v2/api-docs/**",
                "/**/*.js",
                "/**/*.html",
                "/**/*.ico",
                "/**/*.jpg",
                "/**/*.png",
                "/**/*.bmp",
                "/**/*.gif",
                "/**/*.css",
                "/js/**",
                "/html/**",
                "/image/**",
                "/static/**",
                "/druid/**"};
    }
}
